<template>
  <a-spin :spinning="loading" :tip="filePercent_mixin + '%'">
    <a-upload
      :fileList="fileList"
      :beforeUpload="beforeUpload"
      @change="handleChange"
      :customRequest="customRequest"
      :remove="handleRemove"
      @preview="file => parseAloneToUseUrl(file)"
      :multiple="multiple"
    >
      <a-button>上传</a-button>
    </a-upload>
  </a-spin>
</template>

<script>
import { _downFile, base64Encode } from '@/utils/util'
import _ from 'lodash'
import uploadFileMixins from '@/mixins/uploadFileMixins'
import { Message } from '@arco-design/web-vue'
export default {
  name: 'MUpload',
  mixins: [uploadFileMixins],
  props: {
    multiple: {
      type: Boolean,
      default: true
    },
    value: {
      type: String,
      default: () => ''
    },
    exeRawData: {
      type: Object,
      default: () => ({})
    },
    item: {
      type: Object,
      default: () => ({})
    }
  },
  model: {
    prop: 'value',
    event: 'change'
  },
  data () {
    return {
      fileList: [],
      loading: false
    }
  },
  watch: {
    value: {
      handler (newValue) {
        // 确保当父组件更新时，子组件的数据也同步更新
        this.fileList = this.handleValueToList(newValue)
      },
      immediate: true
    }
  },
  methods: {
    handleValueToList (value) {
      if (!value) {
        return []
      }
      return value?.split(',')?.map(fileName => {
        return {
          fileName: fileName,
          name: fileName.split('/').pop() || fileName,
          uid: fileName,
          url: fileName
        }
      }) || []
    },
    beforeUpload (file) {
      // 在这里可以添加一些对文件的预处理逻辑
      const { maxSize } = this.item
      if (maxSize && file.size > maxSize * 1024 * 1024) {
        Message.error(`文件大小不能超过${maxSize}MB`)
        return false
      }
      this.$emit('input', [...this.fileList, file].map(item => item.fileName).join(','))
      return true // 返回 false 来阻止默认上传行为，因为我们可能会用 customRequest 来替代它
    },
    handleChange (info) {
      if (info.file.status === 'done') {
        // 当文件上传成功后，你可以根据返回的结果做相应处理
        this.$emit('change', info.fileList.map(item => item.fileName).join(','))
      } else if (info.file.status === 'error') {
        // 处理错误情况
      }
    },
    handleRemove (file) {
      const index = this.fileList.indexOf(file)
      const newFileList = this.fileList.slice()
      newFileList.splice(index, 1)
      this.$emit('change', newFileList.map(item => item.fileName).join(','))
      return true
    },
    async customRequest (option) {
      // 实现你自己的上传逻辑，比如调用API上传文件
      try {
        this.loading = true
        const { file } = option
        const { name, fileName, url } = await this.uploadClientFile(file)
        Object.defineProperty(option.file, 'name', {
          writable: true
        })
        option.file.name = name
        option.file.fileName = fileName
        option.file.url = url
        // 真实地址库插入真实地址
        Object.assign(this.exeRawData, {
          fileMapUrl: Object.assign({}, this.exeRawData?.fileMapUrl || {}, { [fileName]: url })// 文件名解析真实地址
        })
        // 注意：你需要手动处理进度、完成等状态
        option.onSuccess('fake response')
        // 创建新的文件对象，以确保响应性
        const updatedFile = {
          ...file,
          name: name,
          fileName: fileName,
          url: url,
          status: 'done' // 假设上传完成后状态为 done
        }
        // 更新 fileList 数组，使用 Vue.set 或者 push 新元素以确保响应性
        this.fileList = [...this.fileList.filter(item => item.uid !== file.uid), updatedFile]

        // 触发 change 事件通知父组件
        this.$emit('change', this.fileList.map(item => item.fileName).join(','))
      } catch (e) {
        console.error('Error uploading file:', e)
      } finally {
        this.loading = false
      }
    },
    // 获取真实url
    async parseAloneToUseUrl (file) {
      console.log(file, this.exeRawData.fileMapUrl)
      const fileName = file.originFileObj?.fileName || file.fileName
      if (!_.has(this.exeRawData.fileMapUrl, fileName)) {
        await this.requestAloneImageUrl(fileName)
      }
      const { allowDownload } = this.item || {}
      const url = !_.isEmpty(this.exeRawData?.fileMapUrl) ? (this.exeRawData.fileMapUrl[fileName] || fileName) : fileName
      const address = process.env.VUE_APP_PREVIEW_ADDRESS
      if (/^(http|https)/.test(fileName) || this.isCompressedFile(fileName)) { // 外部文件或压缩文件
        return _downFile(url)
      } else { // 内部文件
        // 判断是否允许下载
        return _downFile(!allowDownload ? address + encodeURIComponent(base64Encode(url)) : url)
      }
    },
    async requestAloneImageUrl (fileName) {
      return new Promise(async (resolve) => {
        const reg = /^(http|https)/ // http或https开头不需要解析
        if (!reg.test(fileName)) {
          const fileNameList = [fileName]
          if (fileNameList.length) {
            try {
              const result = await this.$http.post('file/queryFileUrlList', { fileNameList })
              Object.assign(this.exeRawData, {
                fileMapUrl: Object.assign({}, this.exeRawData?.fileMapUrl || {}, result?.data || {})// 文件名解析真实地址
              })
            } catch (error) {
              console.error('Error fetching file URLs:', error)
            }
          }
        }
        // 确保无论是否执行了异步操作，最终都会调用resolve以结束Promise
        resolve()
      })
    },
    isCompressedFile (url) {
      // 判断是否为压缩包
      const compressedExtensions = ['.zip', '.rar', '.tar', '.gz', '.7z', '.bz2', '.tar.gz']
      return compressedExtensions.some(ext => url.endsWith(ext))
    }
  }
}
</script>

<style lang="less" scoped>
/*解决上传文件名字过长*/
/deep/ .ant-upload-list-item-info {
  a {
    width: 240px;
  }
}
</style>
